1. 如何讓panic,包含一個值
在呼叫panic函數時,把某個值做為參數傳給該函數就可以了。panic函數的唯一一個參數是空接口(interface{})類型,也就是可以接受任何類型的值。但是,最好還是傳入error類型的錯誤值。如下面的範例。
package main
import (
"errors"
"fmt"
)
func main() {
fmt.Println("Enter function main.")
panic(errors.New("something wrong"))
fmt.Println("Exit function main.") //不會被執行到,因為前一行發生panic
}
https://play.golang.org/p/aQ8eUyyBN1A
2. 正確使用recover函數
Go語言的內建函數recover,專門用於恢復panic。recover函數不用任何參數,並且會返回一個空接口類型的值。
什麼時候呼叫recover?
在panic發生之後? 不行,發生panic後,之後的程式碼都不會被執行到。
那放在panic之前呢? 也不行,因為呼叫recover函數時,並沒有發生panic,那麼recover函數就不會做任何事情,並且回傳nil。
這時候,就要用到defer語句了。defer語句的用途,延遲執行程式代碼。
延遲到什麼時候? 延遲到該defer語句的函數即將結束執行的時候。
因此,要恢復panic,需要聯合調用defer語句和recover函數。
package main
import (
"errors"
"fmt"
)
func main() {
fmt.Println("Enter function main.")
defer func() {
fmt.Println("Enter defer function.")
if p := recover(); p != nil {
fmt.Printf("panic: %s\n", p)
}
fmt.Println("Exit defer function.")
}()
panic(errors.New("something wrong"))
fmt.Println("Exit function main.")
}
https://play.golang.org/p/bJ20LIjtwDG
3. 函數中有多個defer語句,執行的順序是?
"defer函數的呼叫與其所屬的defer語句的執行順序完全相反"
也就是說,寫在最下面的defer函數會先被執行,其次,是寫在它上面的defer函數,而最上面的defer函數,會是最後才被呼叫。
在defer語句每次執行的時候,Go語言會把defer函數,儲存到一個Queue中,而這個Queue是FILO。
package main
import "fmt"
func main() {
defer fmt.Println("first defer")
for i := 0; i < 3; i++ {
defer fmt.Printf("defer in for [%d]\n", i)
}
defer fmt.Println("last defer")
}
https://play.golang.org/p/kvGq_JCfG3v
參考來源:
郝林-Go语言核心36讲
https://github.com/hyper0x/Golang_Puzzlers